#!/usr/bin/env python
# -*- coding:utf-8 -*-

'''
/*
 * 事件总线
 *
 * 历史
 *  2020-02-26 姚彧 创建   
 */
'''

__all__ = ['EventContext', 'EventBus', 'appEventBus', 'HandlerDecorator']

class EventContext(object):
    def __repr__(self):
        res = []
        for prop in dir(self):
            if not prop.startswith('_'):
                res.append('%s: %s' % (prop, getattr(self, prop)))
        return ', '.join(res)

class EventBus(object):
    '''事件总线'''
    def __init__(self, handlers:dict=None):
        self._slots = {}
        self._handlers = handlers if handlers else {}

    def __contains__(self, event_name):
        assert(event_name)
        return event_name in self._slots

    def emit(self, fire_event_name, context, *args, **kwargs):
        assert (isinstance(context, EventContext))
        bfind = 0
        for event_name in ('*', fire_event_name):
            if event_name in self._slots:
                for handler in self._slots[event_name]:
                    if (event_name == fire_event_name):
                        bfind = 1
                    res = handler(context, *args, **kwargs)
                    if res:
                        return res
        if not bfind:
            print('事件未响应: (%s,%s,%s)' % (fire_event_name, args, kwargs))
    __call__ = emit

    def bind(self, event_name, handler=None):
        assert(event_name)
        if not handler:
            assert(event_name in self._handlers)
            handler = self._handlers[event_name]
        assert (handler)

        if (event_name not in self._slots):
            self._slots[event_name] = []
        slot = self._slots[event_name]
        if(handler not in slot):
            slot.append(handler)

        assert(event_name in self._slots)
        assert(handler in self._slots[event_name])

    def unbind(self, event_name, handler=None):
        if not handler:
            assert(event_name in self._handlers)
            handler = self._handlers[event_name]
        if (event_name in self._slots) and (handler in self._slots[event_name]):
            self._slots[event_name].remove(handler)
            assert handler not in self._slots[event_name]

    def clear_event(self, event_name):
        if event_name in self._slots:
            del self._slots[event_name]

    def clear(self):
        self._slots.clear()


#
#  装饰器
#

def HandlerDecorator(handler):
    def _(context, *args, **kwdargs):
        return handler(*args, **kwdargs)
    return _


#
#  实例化全局消息派发器
#

appEventBus = EventBus({})

print('EventBus loaded.')

if __name__ == '__main__':

    import unittest
    class CTest(unittest.TestCase):
        def test001(self):
            context = EventContext()
            aEventBus = EventBus({})
            aEventBus.bind('*',  HandlerDecorator(print))
            aEventBus.emit('fdf', context, 'a', 'b', 'c')
            aEventBus.emit('f',context, 'b')
            aEventBus.emit('fd',context, 'ab你做错了')
            aEventBus.emit('*',context, print)
            aEventBus.emit('fffffffffffff',context, 'fdddddddddddddddddddddddda')
            
    unittest.main()

